///////////////////////////////////////////////////////////////////////////////
//
// Licensed under the MIT License
//
// Copyright (c) 2010 Chris Colinsky
// All Rights Reserved
//
// version	0.5
// http://code.google.com/p/sugarcookie/
// http://code.google.com/p/sugarcookie/wiki/License
//
////////////////////////////////////////////////////////////////////////////////

package sugarcookie.components.videoPlayer {
	import flash.display.Sprite;
	
	import sugarcookie.commands.DynamicCommand;
	import sugarcookie.display.SpriteBase;
	import sugarcookie.error.ApplicationError;
	import sugarcookie.media.IVideoSource;
	import sugarcookie.media.VideoSourceConstants;
	import sugarcookie.notifications.Notification;
	import sugarcookie.ui.IUIButton;
	import sugarcookie.utils.IObserver;
	
	public class VideoPlayer extends SpriteBase implements IObserver {
		protected var _background:Sprite;
		protected var _playPauseBtn:IUIButton;
		protected var _seekBar:BasicSeekBar;
		protected var _timecode:BasicTimecode;
		protected var _video:IVideoSource;
		protected var _volumeBtn:IVolumeButton;
		protected var _uiContainer:Sprite;
		protected var _videoOverlay:IObserver;
		
		private var _controls:VideoController;
		
		private var _playList:PlayList;
		
		private var _isStreamReady:Boolean = false;
		private var _waiting:Boolean = false;
		
		public function VideoPlayer(props:Object=null) {
			super(props);
			
			_controls = new VideoController();
			addChild(_uiContainer = new Sprite());
			assignGraphics();
			internal_init();
		}
		
		final public function set useLogging(value:Boolean):void {
			_video.useLogging = _controls.useLogging = value;
		}
		
		final public function addUIComponent(component:Sprite,receiveNotifications:Boolean=false):void {
			_uiContainer.addChild(component);
			if (receiveNotifications && component is IObserver) _controls.addObserver(IObserver(component));
		}
		
		final public function set playList(value:PlayList):void {
			_playList = value;
			if (_playList.autoStart) start();
		}
		
		final public function close():void {
			_controls.reset();
			reset();
		}
		
		final public function start():void {
			if (_isStreamReady) {
				if (_playList==null) throw new ApplicationError("No PlayList has been defined!");
				_controls.start_playback(_playList);
			} else {
				_waiting = true;
			}
		}
		
		final public function update(notification:Notification):void {
			switch (notification.type) {
				case VideoSourceConstants.STREAM_READY:
					_video.removeObserver(this,VideoSourceConstants.STREAM_READY);
					_isStreamReady = true;
					if (_volumeBtn) _volumeBtn.volume = _video.volume;
					if (_waiting) {
						_waiting = false;
						start();
					}
					break;
				case VideoSourceConstants.STATUS_CHANGE:
					if (notification.data.code=="NetStream.Play.Start") {
						if (_playPauseBtn) _playPauseBtn.toggle(VideoController.PLAY);
						playbackInit();
					}
					break;
				case VideoSourceConstants.QUALITY_CHANGE:
					qualityUpdate();
					break;
				case VideoController.RESET:
					internal_reset();
					break;
				case VideoController.PLAYLIST_COMPLETE:
					complete();
					break;
				case VideoController.LOCK_CONTROLS:
					if (_playPauseBtn) _playPauseBtn.active = !notification.data.status;
					break;
			}
		}
		
		protected function assignGraphics():void {
			// to be overridden in the subclass
			throw new ApplicationError("Graphics must be assigned!");
		}
		
		protected function qualityUpdate():void {
			// to be overridden in the subclass
			_log.debug("VideoPlayer.qualityUpdate() is called when the video quality is updated, only applies when using YouTube video.  Override to add custom functionality.");
		}
		
		protected function playbackInit():void {
			// to be overridden in the subclass
			_log.debug("VideoPlayer.playbackInit() is called when the video begins to play, not necessarily at the beginning.  Override to add custom functionality.");
		}
		
		protected function complete():void {
			// to be overridden in the subclass
			_log.debug("VideoPlayer.complete() is called when the playlist has completed all playback of its items.  Override to add custom functionality.");
		}
		
		protected function reset():void {
			// to be overridden in the subclass
			_log.debug("VideoPlayer.reset() is called during stopPlayback().  Override to add custom reset functionality.");
		}
		
		final protected function set background(value:Sprite):void { addChild(_background = value); }
		
		final protected function set video(value:IVideoSource):void { 
			_video = value;
			addChild(Sprite(value)); 
		}
		
		final protected function set playPauseBtn(value:IUIButton):void {
			_playPauseBtn = value;
			_uiContainer.addChild(Sprite(value)); 
			_playPauseBtn.command = new DynamicCommand(_controls,"playPauseToggle");
			_playPauseBtn.active = false;
		}
		
		final protected function set seekBar(value:BasicSeekBar):void { 
			_uiContainer.addChild(_seekBar = value); 
			_seekBar.isStreaming = _video.isStreaming;
		}
		
		final protected function set timecode(value:BasicTimecode):void { _uiContainer.addChild(_timecode = value); }
		
		final protected function set volumeBtn(value:IVolumeButton):void {
			_volumeBtn = value;
			_uiContainer.addChild(Sprite(_volumeBtn));
			_volumeBtn.command = new DynamicCommand(_controls,"volume");
		}
		
		final protected function set videoOverlay(value:IObserver):void { 
			_videoOverlay = value;
			_uiContainer.addChild(Sprite(_videoOverlay));
			_controls.addObserver(_videoOverlay);
		}
		
		private function internal_init():void {
			setChildIndex(_uiContainer,numChildren-1);
			
			_video.addObserver(this,VideoSourceConstants.STREAM_READY);
			_video.addObserver(this,VideoSourceConstants.STATUS_CHANGE);
			_video.addObserver(this,VideoSourceConstants.QUALITY_CHANGE);
			_video.connect();
			
			_controls.addObserver(this,VideoController.RESET);
			_controls.addObserver(this,VideoController.PLAYLIST_COMPLETE);
			_controls.addObserver(this,VideoController.LOCK_CONTROLS);
			_controls.init(_video,_seekBar,_timecode);
		}
		
		private function internal_reset():void {
			if (_playPauseBtn) _playPauseBtn.toggle(VideoController.PAUSE);
		}
	}
}